if(!GPS_Device_On(port, &fd))
return gps_errno;
- if ((trk_type == pD304) && gps_run_transfer != -1) {
+ if (protoid == 301 && trk_type == pD304 && gps_run_transfer != -1) {
drain_run_cmd(fd);
}
UC data[GPS_ARB_LEN];
GPS_PPacket tra;
GPS_PPacket rec;
- int32 i, j;
+ int32 i;
int32 len;
US method;
US Pid_Trk_Data, Pid_Trk_Hdr, Cmnd_Transfer_Trk;
return GPS_UNSUPPORTED;
}
- /* D303/304 marks track segments with two consecutive invalid track
- * points. Create them unless we're at the beginning of a track or there
- * are already invalid track points (because the track was downloaded
- * using D303/304). This needs to be done here because it will change
- * the number of track points.
- */
- if (trk_type == pD303 || trk_type == pD304)
- {
- for(i=0;i<n;++i)
- {
- if (trk[i]->tnew && i>0 && !trk[i]->ishdr && !trk[i-1]->ishdr)
- {
- /* Create in reverse order to avoid having to readjust the
- * index after inserting the first point.
- */
- for (j=i; j>=i-1; j--)
- {
- if (!Is_Trackpoint_Invalid(trk[j]))
- {
- GPS_PTrack trkpt = GPS_Track_New();
- *trkpt = *(trk[j]);
- trkpt->no_latlon = 1;
- trkpt->alt = 1e25;
- trkpt->distance_populated = 0;
- trkpt->heartrate = 0;
- trkpt->cadence = 0xff;
- trk = xrealloc(trk, (n+1) * sizeof(GPS_PTrack));
- memmove(&trk[i+1], &trk[i], (n-i) * sizeof(GPS_PTrack));
- n++;
- trk[i] = trkpt;
- }
- }
- }
- }
- }
-
if(protoid != 302 && !GPS_Device_On(port, &fd))
return gps_errno;
}
+/* @func GPS_A1009_Get ******************************************************
+**
+** Get course limits from GPS
+**
+** @param [r] port [const char *] serial port
+** @param [w] limits [GPS_PCourse_Limits] course limits structure
+**
+** @return [int32] success
+************************************************************************/
+
+int32 GPS_A1009_Get(const char *port, GPS_PCourse_Limits limits)
+{
+ static UC data[2];
+ gpsdevh *fd;
+ GPS_PPacket trapkt;
+ GPS_PPacket recpkt;
+
+ if (gps_course_limits_transfer == -1)
+ return GPS_UNSUPPORTED;
+
+ if (!GPS_Device_On(port, &fd))
+ return gps_errno;
+
+ if (!(trapkt = GPS_Packet_New() ) || !(recpkt = GPS_Packet_New()))
+ return MEMORY_ERROR;
+
+ GPS_Util_Put_Short(data,
+ COMMAND_ID[gps_device_command].Cmnd_Transfer_Course_Limits);
+ GPS_Make_Packet(&trapkt, LINK_ID[gps_link_type].Pid_Command_Data,
+ data,2);
+ if(!GPS_Write_Packet(fd,trapkt))
+ return gps_errno;
+ if(!GPS_Get_Ack(fd, &trapkt, &recpkt))
+ return gps_errno;
+ if(!GPS_Packet_Read(fd, &recpkt))
+ return gps_errno;
+ if(!GPS_Send_Ack(fd, &trapkt, &recpkt))
+ return gps_errno;
+
+ switch(gps_course_limits_type) {
+ case pD1013:
+ GPS_D1013_Get(limits,recpkt->data);
+ break;
+ default:
+ GPS_Error("A1009_Get: Unknown Course Limits protocol %d\n",
+ gps_course_limits_type);
+ return PROTOCOL_ERROR;
+ }
+
+ GPS_Packet_Del(&trapkt);
+ GPS_Packet_Del(&recpkt);
+
+ if (!GPS_Device_Off(fd))
+ return gps_errno;
+ return 1;
+}
+
+
+/* @func GPS_D1013_Get ******************************************************
+**
+** Convert packet D1013 to course limits structure
+**
+** @param [w] limits [GPS_PCourse_Limits] course limits structure
+** @param [r] p [UC *] packet data
+**
+** @return [void]
+************************************************************************/
+void GPS_D1013_Get(GPS_PCourse_Limits limits, UC *p)
+{
+ limits->max_courses = GPS_Util_Get_Uint(p);
+ p+=sizeof(uint32);
+
+ limits->max_course_laps = GPS_Util_Get_Uint(p);
+ p+=sizeof(uint32);
+
+ limits->max_course_pnt = GPS_Util_Get_Uint(p);
+ p+=sizeof(uint32);
+
+ limits->max_course_trk_pnt = GPS_Util_Get_Uint(p);
+ p+=sizeof(uint32);
+}
+
+
/*
* It's unfortunate that these aren't constant and therefore switchable,
* but they really are runtime variable. Sigh.
return trk->no_latlon && trk->distance > 1e24 &&
!trk->heartrate && !trk->cadence;
}
+
+
+/* @func GPS_Prepare_Track_For_Device **********************************
+**
+** Perform device-specific adjustments on a track before upload.
+**
+** @param [r] trk [GPS_PTrack **] track
+** @param [r] n [int32 *] Number of trackpoints
+************************************************************************/
+void GPS_Prepare_Track_For_Device(GPS_PTrack **trk, int32 *n)
+{
+ int32 i, j;
+
+ /* D303/304 marks track segments with two consecutive invalid track
+ * points instead of the tnew flag. Create them unless we're at the
+ * beginning of a track or there are already invalid track points
+ * (because the track was downloaded using D303/304). This needs to be
+ * done here because it will change the number of track points.
+ */
+ if (gps_trk_type == pD303 || gps_trk_type == pD304)
+ {
+ for(i=0;i<*n;++i)
+ {
+ if ((*trk)[i]->tnew && i>0 && !(*trk)[i]->ishdr && !(*trk)[i-1]->ishdr)
+ {
+ /* Create invalid points based on the data from the point
+ * marked with tnew and the one before it.
+ */
+ for (j=i-1; j<=i; j++)
+ {
+ if (!Is_Trackpoint_Invalid((*trk)[j]))
+ {
+ GPS_PTrack trkpt = GPS_Track_New();
+ *trkpt = *((*trk)[j]);
+ trkpt->no_latlon = 1;
+ trkpt->alt = 1e25;
+ trkpt->distance_populated = 0;
+ trkpt->heartrate = 0;
+ trkpt->cadence = 0xff;
+ *trk = xrealloc(*trk, (*n+1) * sizeof(GPS_PTrack));
+ memmove(&(*trk)[i+1], &(*trk)[i], (*n-i) * sizeof(GPS_PTrack));
+ (*trk)[i] = trkpt;
+ i++;
+ j++;
+ (*n)++;
+ }
+ }
+ }
+ }
+ }
+}
void GPS_D1012_Get(GPS_PCourse_Point *cpt, UC *p);
void GPS_D1012_Send(UC *data, GPS_PCourse_Point cpt, int32 *len);
+int32 GPS_A1009_Get(const char *port, GPS_PCourse_Limits limits);
+void GPS_D1013_Get(GPS_PCourse_Limits limits, UC *p);
+
/* Unhandled documented protocols, as of:
Garmin Device Interface Specification, May 19, 2006, Drawing Number: 001-00063-00 Rev. C
A650 FlightBook Transfer Protocol
Capability A1004: D1004
A1005 Workout Limits Transfer Protocol
Capability A1005: D1005
-A1009 Course Limits Transfer Protocol
- Capability A1009: D1013
*/
/* Unimplemted and Undocumented, as listed from the following device/sw:
GF305 3.70
const char * Get_Pkt_Type(US p, US d0, const char **xinfo);
+void GPS_Prepare_Track_For_Device(GPS_PTrack **trk, int32 *n);
#endif
int32 n_cpt)
{
gpsdevh *fd;
+ GPS_OCourse_Limits limits;
+ int32 ret;
int32 ret_crs=0;
int32 ret_clp=0;
int32 ret_trk=0;
int32 ret_cpt=0;
- if(gps_course_transfer == -1)
+ if(gps_course_transfer == -1 || gps_course_limits_transfer == -1)
return GPS_UNSUPPORTED;
+ /* Check course limits to make sure we're not exceeding the device's
+ * capacity.
+ */
+ switch(gps_course_limits_transfer)
+ {
+ case pA1009:
+ ret = GPS_A1009_Get(port,&limits);
+ break;
+ default:
+ GPS_Error("Send_Course: Unknown course limitsprotocol");
+ return PROTOCOL_ERROR;
+ }
+
+ if (n_crs > limits.max_courses
+ || n_clp > limits.max_course_laps
+ || n_trk > limits.max_course_trk_pnt
+ || n_cpt > limits.max_course_pnt)
+ {
+ GPS_Error("Course upload would exceed device capacity:");
+ GPS_Error("# of courses: %d, max: %d", n_crs, limits.max_courses);
+ GPS_Error("# of laps: %d, max: %d", n_clp, limits.max_course_laps);
+ GPS_Error("# of track points: %d, max: %d", n_trk, limits.max_course_trk_pnt);
+ GPS_Error("# of course points: %d, max: %d", n_cpt, limits.max_course_pnt);
+ return GPS_UNSUPPORTED;
+ }
+
/* Initialize device communication:
* In contrast to other transfer protocols, this has to be handled here;
* shutting off communication in between the different parts
if (trk[trk_end+1]->ishdr)
break;
if (trk_end==i)
- trk_end=0; /* Empty track */
+ continue; /* Skip empty track */
/* Create & append course */
crs = xrealloc(crs, (n_crs+1) * sizeof(GPS_PCourse));
/* Append new track points */
ctk = xrealloc(ctk, (n_ctk+n_trk) * sizeof(GPS_PTrack));
-
first_new_ctk = n_ctk;
for (i=0;i<n_trk;i++) {
+ if (trk[i]->ishdr && (i>=n_trk || trk[i+1]->ishdr))
+ continue;
+
ctk[n_ctk] = GPS_Track_New();
if (!ctk[n_ctk]) return MEMORY_ERROR;
*ctk[n_ctk] = *trk[i];
- if (ctk[n_ctk]->ishdr)
+ if (trk[i]->ishdr)
{
/* Index of new track, must match the track index in associated course */
memset(ctk[n_ctk]->trk_ident, 0, sizeof(ctk[n_ctk]->trk_ident));
int min_dist_idx = 0, trk_idx = 0, min_dist_trk_idx = 0;
/* Find closest track point */
- for (j=first_new_ctk; j<first_new_ctk+n_trk; j++) {
+ for (j=first_new_ctk; j<n_ctk; j++) {
if (ctk[j]->ishdr) {
trk_idx = strtoul(ctk[j]->trk_ident, NULL, 0);
continue;